#ifndef THINKING_COMPONENT_H_
#define THINKING_COMPONENT_H_

#include "../backend/CBSEBackend.h"
#include "../backend/CBSEComponents.h"

#include <functional>

class ThinkingComponent: public ThinkingComponentBase {
	public:
		enum thinkScheduler_t {
			SCHEDULER_CLOSEST,
			SCHEDULER_BEFORE,
			SCHEDULER_AFTER,
			SCHEDULER_AVERAGE
		};

		/**
		 * @brief A function that takes the time since last execution and its fraction of the
		 *        desired period as parameters.
		 */
		typedef std::function<void(int)> thinker_t;

		// ///////////////////// //
		// Autogenerated Members //
		// ///////////////////// //

		/**
		 * @brief Default constructor of the ThinkingComponent.
		 * @param entity The entity that owns the component instance.
		 * @param r_DeferredFreeingComponent A DeferredFreeingComponent instance that this component depends on.
		 * @note This method is an interface for autogenerated code, do not modify its signature.
		 */
		ThinkingComponent(Entity& entity, DeferredFreeingComponent& r_DeferredFreeingComponent);

		// ///////////////////// //

		void Think();

		int GetLastThinkTime() const;
		void RegisterThinker(thinker_t thinker, thinkScheduler_t scheduler, int period);
		void UnregisterActiveThinker();

	private:
		struct thinkRecord_t {
			thinker_t thinker;
			thinkScheduler_t scheduler;
			int period;
			int timestamp; /**< Time of last thinker execution. */
			int delay; /**< Summed lateness of previous executions. */
			bool unregister;
		};

		std::vector<thinkRecord_t> thinkers;

		bool iteratingThinkers;
		std::vector<thinkRecord_t> newThinkers; /**< Used for adding thinkers during iteration over them. */

		bool unregisterActiveThinker;

		float averageFrameTime; /**< Smoothed out average frame time for predictions. */

		constexpr static float averageChangeRate = 0.1f;

		int lastThinkRound; /**< Used to make sure that we think at most once per frame. */
};

#endif // THINKING_COMPONENT_H_
